package world.square;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;

import world.placement.Direction;

/**
 * Class representing a teleportation square. 
 * 
 * @author Frederic Mes, Wim Marynissen
 * @version 1.0
 */
public class NormalTeleport extends Square implements Teleportation{
	
	/**
	 * Variable holding the possible destinations to teleport to.
	 */
	private List<Square> destinations = new ArrayList<Square>();
	
	/**
     * Create a new teleportation square.
     * @param	temperature
	 * 			The temperature of the new square.
	 * @param	humidity
	 * 			The humidity of the new square
	 * @param	destinations
	 * 			A list of possible destinations for teleportation.
	 * @param	directions
	 * 			The directions in which to add a wall.
     * @effect 	This normal square is initialized as square with given characteristics.
     *          | super(temperature, humidity, directions)
     * @post	The specified destinations are added to this square.
     * 			| for each destination in destinations
     * 			|	(new this).getDestinations().contains(destination)
     */
    public NormalTeleport(Temperature temperature, BigDecimal humidity, List<Square> destinations, Direction... directions) throws IllegalArgumentException {
        super(temperature, humidity, directions);
        addDestinations(destinations);
    }
    
	/**
	 * @param	destinations
	 * 			A list of possible destinations for teleportation.
	 * @param	directions
	 * 			The directions in which to add a wall.
	 * @effect	Standard initialization, with the specified directions for borders.
	 * 			| super(directions)
	 * @post	The specified destinations are added to this square.
     * 			| for each destination in destinations
     * 			|	(new this).getDestinations().contains(destination)
	 */
	public NormalTeleport(List<Square> destinations,Direction... directions){
		super(directions);
		addDestinations(destinations);
	}

	/**
	 * Static field containing a random generator.
	 */
	private static Random random = new Random();
	
	
	/**
	 * Get a random destination.
	 */
	public Square randomDestination() {
        int randInt = random.nextInt(this.getDestinations().size());
        while (this.getDestinations().get(randInt) == null){
        	randInt = random.nextInt(this.getDestinations().size());
        }
        return this.getDestinations().get(randInt);
	}

	/**
	 * Return the destinations of this teleporation square.
	 */
	@Basic
	public List<Square> getDestinations() {
		return destinations;
	}

	/**
     * Check if the specified square is a destination of this teleportation square.
     */
	public boolean hasDestination(Square destination) {
		return (destination != null) && getDestinations().contains(destination);
	}

	/**
     * Check if the square can be used as destination for teleportation.
     */
	public boolean isValidDestination(Square square) {
		return ((square != null)
					&& !(square instanceof Rock) 
						&& !(square.equals(this)));
	}
	
	/**
     * Check if the provided square can be removed from the destinations.
     */
	public boolean canRemoveDestination(Square square){
		if(square == null)
			return false;
		return destinations.contains(square);
	}
	
	/**
     * Add a number of destinations to the teleportation square.
     */
	@Raw
	public void addDestinations(List<Square> destinations) {
		for (Square destination : destinations){
			assert(isValidDestination(destination));
			addDestination(destination);
		}
		
	}
	
	/**
     * Add a destination to the teleportation square.
     */
	@Raw
	public boolean addDestination(Square destination) {
		assert(isValidDestination(destination));
		if(!(getDestinations().contains(destination))){
			return this.destinations.add(destination);
		}
		return true;
		
	}
	/**
     * Remove some of the destination squares.
     */
	public void removeDestinations(List<Square> destinations) {
		for (Square destination : destinations){
			assert(canRemoveDestination(destination));
			removeDestination(destination);
		}
	}
	/**
     * Add a destination to the teleportation square.
     */
	public boolean removeDestination(Square destination) { 
		assert(canRemoveDestination(destination));
		return this.destinations.remove(destination);		
	}
}
